#include "manano_common.h"

#include "mdtx-online/indicator/indicator_type_misc.h"
#include "mdtx-online/indicator/indicator_type_ma.h"
#include "mdtx-online/indicator/indicator_type_ordered.h"
#include "mdtx-online/indicator/indicator_type_s2_zscore.h"
namespace indi = mdtx::online::indicator;

using rollsum = unary1<indi::rollsum>;
using ad = quadary1<indi::ad>;
using adosc = quadary1<indi::adosc>;
using atr = ternary1<indi::atr>;
using bop = quadary1<indi::bop>;
using cmo = unary1<indi::cmo>;
using cvi = binary1<indi::cvi>;
using dpo = unary1<indi::dpo>;
using emv = ternary1<indi::emv>;
using mass = unary1<indi::mass>;
using mfi = binary1<indi::mfi>;
using obv = binary1<indi::obv>;
using pmomentum = unary3<indi::pmomentum>;
using pmomentum_ew = unary3<indi::pmomentum_ew>;
using psar = binary2<indi::psar>;
using stosc = ternary1<indi::stosc>;
using vhf = unary1<indi::vhf>;
using volidx = binary2<indi::volidx>;
using wad = ternary1<indi::wad>;
using willr = ternary1<indi::willr>;
// from ma
using trix = unary1<indi::trix>;
// from ordered
using aroonosc = binary1<indi::aroonosc>;
// from zscore
using cci = unary1<indi::cci>;


void bind_indi(py::module &m)
{
    auto mod = m.def_submodule("indi", "Miscellaneous indicators");
    {
        auto v = py::class_<rollsum>(mod, "rollsum")
                     .def(py::init<int>(), py::arg("period"))
                     .def("run", &rollsum::run, py::arg("x"), "Run calc")
                     .def("run", &rollsum::run2, py::arg("x"), "Run batch calc");
        v.doc() = R"mydoc(
                    Rolling sum
                    Args:
                        period (int) : rolling window period)mydoc";
    }
    {
        auto v = py::class_<ad>(mod, "ad")
                     .def(py::init())
                     .def("run", &ad::run, py::arg("high"), py::arg("low"), py::arg("close"), py::arg("vol"), "Run calc")
                     .def("run", &ad::run2, py::arg("high"), py::arg("low"), py::arg("close"), py::arg("vol"), "Run batch calc");
        v.doc() = R"mydoc(
                    Accumulation/distribution)mydoc";
    }
    {
        auto v = py::class_<adosc>(mod, "adosc")
                     .def(py::init<int, int>(), py::arg("fast_period"), py::arg("slow_period"))
                     .def("run", &adosc::run, py::arg("high"), py::arg("low"), py::arg("close"), py::arg("vol"), "Run calc")
                     .def("run", &adosc::run2, py::arg("high"), py::arg("low"), py::arg("close"), py::arg("vol"), "Run batch calc");
        v.doc() = R"mydoc(
                    Accumulation/distribution oscillator
                    Args:
                        fast_period (int) : fast MA period
                        slow_period (int) : slow MA period)mydoc";
    }
    {
        auto v = py::class_<atr>(mod, "atr")
                     .def(py::init<int>(), py::arg("period"))
                     .def("run", &atr::run, py::arg("high"), py::arg("low"), py::arg("close"), "Run calc")
                     .def("run", &atr::run2, py::arg("high"), py::arg("low"), py::arg("close"), "Run batch calc");
        v.doc() = R"mydoc(
                    Average true range
                    Args:
                        period (int) : rolling window period)mydoc";
    }
    {
        auto v = py::class_<bop>(mod, "bop")
                     .def(py::init())
                     .def("run", &bop::run, py::arg("open"), py::arg("high"), py::arg("low"), py::arg("close"), "Run calc")
                     .def("run", &bop::run2, py::arg("open"), py::arg("high"), py::arg("low"), py::arg("close"), "Run batch calc");
        v.doc() = R"mydoc(
                    Balance of power)mydoc";
    }
    {
        auto v = py::class_<cmo>(mod, "cmo")
                     .def(py::init<int>(), py::arg("period"))
                     .def("run", &cmo::run, py::arg("x"), "Run calc")
                     .def("run", &cmo::run2, py::arg("x"), "Run batch calc");
        v.doc() = R"mydoc(
                    Chande momentum oscillator
                    Args:
                        period (int) : rolling window period)mydoc";
    }
    {
        auto v = py::class_<cvi>(mod, "cvi")
                     .def(py::init<int>(), py::arg("period"))
                     .def("run", &cvi::run, py::arg("high"), py::arg("low"), "Run calc")
                     .def("run", &cvi::run2, py::arg("high"), py::arg("low"), "Run batch calc");
        v.doc() = R"mydoc(
                    Chaikins volatility
                    Args:
                        period (int) : rolling window period)mydoc";
    }
    {
        auto v = py::class_<dpo>(mod, "dpo")
                     .def(py::init<int>(), py::arg("period"))
                     .def("run", &dpo::run, py::arg("x"), "Run calc")
                     .def("run", &dpo::run2, py::arg("x"), "Run batch calc");
        v.doc() = R"mydoc(
                    Detrended price oscillator
                    Args:
                        period (int) : rolling window period)mydoc";
    }
    {
        auto v = py::class_<emv>(mod, "emv")
                     .def(py::init<double>(), py::arg("vol_scaler") = 0.0001)
                     .def("run", &emv::run, py::arg("high"), py::arg("low"), py::arg("vol"), "Run calc")
                     .def("run", &emv::run2, py::arg("high"), py::arg("low"), py::arg("vol"), "Run batch calc");
        v.doc() = R"mydoc(
                    Ease of movement
                    Args:
                        vol_scaler (float64) : a scaling factor to make volume about same magnitude of prices)mydoc";
    }
    {
        auto v = py::class_<mass>(mod, "mass")
                     .def(py::init<int>(), py::arg("period"))
                     .def("run", &mass::run, py::arg("x"), "Run calc")
                     .def("run", &mass::run2, py::arg("x"), "Run batch calc");
        v.doc() = R"mydoc(
                    MASS index
                    Args:
                        period (int) : rolling window period)mydoc";
    }
    {
        auto v = py::class_<mfi>(mod, "mfi")
                     .def(py::init<int>(), py::arg("period"))
                     .def("run", &mfi::run, py::arg("price"), py::arg("turnover"), "Run calc")
                     .def("run", &mfi::run2, py::arg("price"), py::arg("turnover"), "Run batch calc");
        v.doc() = R"mydoc(
                    Money flow index
                    Args:
                        period (int) : rolling window period)mydoc";
    }
    {
        auto v = py::class_<obv>(mod, "obv")
                     .def(py::init())
                     .def("run", &obv::run, py::arg("price"), py::arg("vol"), "Run calc")
                     .def("run", &obv::run2, py::arg("price"), py::arg("vol"), "Run batch calc");
        v.doc() = R"mydoc(
                    On balance volume)mydoc";
    }
    {
        auto v = py::class_<pmomentum>(mod, "pmomentum")
                     .def(py::init<int>(), py::arg("period"))
                     .def("run", &pmomentum::run, py::arg("x"),
                          R"mydoc(
                             Run calculation
                             Args:
                                x (float64) : input data
                             Return:
                                log return (float64)
                                cumulative return (float64)
                                mean return (float64))mydoc")
                     .def("run", &pmomentum::run2, py::arg("x"),
                          R"mydoc(
                             Run calculation
                             Args:
                                x (numpy.array) : input data
                             Return:
                                log return (numpy.array)
                                cumulative return (numpy.array)
                                mean return (numpy.array))mydoc");
        v.doc() = R"mydoc(
                    Price momentum
                    Args:
                        period (int) : rolling window period)mydoc";
    }
    {
        auto v = py::class_<pmomentum_ew>(mod, "pmomentum_ew")
                     .def(py::init<int>(), py::arg("period"))
                     .def("run", &pmomentum_ew::run, py::arg("x"),
                          R"mydoc(
                             Run calculation
                             Args:
                                x (float64) : input data
                             Return:
                                log return (float64)
                                cumulative return (float64)
                                mean return (float64))mydoc")
                     .def("run", &pmomentum_ew::run2, py::arg("x"),
                          R"mydoc(
                             Run calculation
                             Args:
                                x (numpy.array) : input data
                             Return:
                                log return (numpy.array)
                                cumulative return (numpy.array)
                                mean return (numpy.array))mydoc");
        v.doc() = R"mydoc(
                    Exponentially weighted price momentum
                    Args:
                        period (int) : rolling window period)mydoc";
    }
    {
        auto v = py::class_<psar>(mod, "psar")
                     .def(py::init<double, double>(), py::arg("acc_init") = 0.02, py::arg("acc_mac") = 0.2)
                     .def("run", &psar::run, py::arg("high"), py::arg("low"),
                          R"mydoc(
                             Run calculation
                             Args:
                                high (float64) : high price
                                low (float64) : low price
                             Return:
                                SAR (float64)
                                trend (float64))mydoc")
                     .def("run", &psar::run2, py::arg("high"), py::arg("low"),
                          R"mydoc(
                             Run calculation
                             Args:
                                high (numpy.array) : high price
                                low (numpy.array) : low price
                             Return:
                                SAR (numpy.array)
                                trend (numpy.array))mydoc");
        v.doc() = R"mydoc(
                    Parabolic SAR
                    Args:
                        acc_init (float64) : initial accelerate factor (0.02)
                        acc_max (float64) : max accelerate factor (0.2))mydoc";
    }
    {
        auto v = py::class_<stosc>(mod, "stosc")
                     .def(py::init<int>(), py::arg("period"))
                     .def("run", &stosc::run, py::arg("high"), py::arg("low"), py::arg("close"), "Run calc")
                     .def("run", &stosc::run2, py::arg("high"), py::arg("low"), py::arg("close"), "Run batch calc");
        v.doc() = R"mydoc(
                    Stochastic oscillator
                    Args:
                        period (int) : rolling window period)mydoc";
    }
    {
        auto v = py::class_<vhf>(mod, "vhf")
                     .def(py::init<int>(), py::arg("period"))
                     .def("run", &vhf::run, py::arg("x"), "Run calc")
                     .def("run", &vhf::run2, py::arg("x"), "Run batch calc");
        v.doc() = R"mydoc(
                    Vertical horizontal filter
                    Args:
                        period (int) : rolling window period)mydoc";
    }
    {
        auto v = py::class_<volidx>(mod, "volidx")
                     .def(py::init<double>(), py::arg("initial") = 1000.0)
                     .def("run", &volidx::run, py::arg("price"), py::arg("vol"),
                          R"mydoc(
                             Run calculation
                             Args:
                                price (float64) : price
                                vol (float64) : volume
                             Return:
                                positive volume index (float64)
                                negative volume index (float64))mydoc")
                     .def("run", &volidx::run2, py::arg("price"), py::arg("vol"),
                          R"mydoc(
                             Run calculation
                             Args:
                                price (numpy.array) : price
                                vol (numpy.array) : volume
                             Return:
                                positive volume index (numpy.array)
                                negative volume index (numpy.array))mydoc");
        v.doc() = R"mydoc(
                    Volume index
                    Args:
                        initial (float64) : initial volume index (1000.0))mydoc";
    }
    {
        auto v = py::class_<wad>(mod, "wad")
                     .def(py::init())
                     .def("run", &wad::run, py::arg("high"), py::arg("low"), py::arg("close"), "Run calc")
                     .def("run", &wad::run2, py::arg("high"), py::arg("low"), py::arg("close"), "Run batch calc");
        v.doc() = R"mydoc(
                    Williams accumulation/distribution)mydoc";
    }
    {
        auto v = py::class_<willr>(mod, "willr")
                     .def(py::init<int>(), py::arg("period"))
                     .def("run", &willr::run, py::arg("high"), py::arg("low"), py::arg("close"), "Run calc")
                     .def("run", &willr::run2, py::arg("high"), py::arg("low"), py::arg("close"), "Run batch calc");
        v.doc() = R"mydoc(
                    Williams R percentage
                    Args:
                        period (int) : rolling window period)mydoc";
    }
    // from ma
    {
        auto v = py::class_<trix>(mod, "trix")
                     .def(py::init<int>(), py::arg("period"))
                     .def("run", &trix::run, py::arg("x"), "Run calc")
                     .def("run", &trix::run2, py::arg("x"), "Run batch calc");
        v.doc() = R"mydoc(
                    TRIX indicator (high-freq of triple EMA)
                    Args:
                        period (int) : MA period)mydoc";
    }
    // from ordered
    {
        auto v = py::class_<aroonosc>(mod, "aroonosc")
                     .def(py::init<int>(), py::arg("period"))
                     .def("run", &aroonosc::run, py::arg("high"), py::arg("low"), "Run calc")
                     .def("run", &aroonosc::run2, py::arg("high"), py::arg("low"), "Run batch calc");
        v.doc() = R"mydoc(
                    Aroon oscillator
                    Args:
                        period (int) : rolling window period)mydoc";
    }
    // from zscore
    {
        auto v = py::class_<cci>(mod, "cci")
                     .def(py::init<int>(), py::arg("period"))
                     .def("run", &cci::run, py::arg("x"), "Run calc")
                     .def("run", &cci::run2, py::arg("x"), "Run batch calc");
        v.doc() = R"mydoc(
                    Commodity channel index
                    CCI is essentially standard rolling zscore, but uses MAE (mean average error) as scale
                    Args:
                        period (int) : rolling window period)mydoc";
    }
}
